package com.aya.mybatis.core.plugin;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;

import javax.persistence.GeneratedValue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.util.Properties;
import java.util.Random;
import java.util.UUID;

/**
 * @author by liushang@zsyjr.com
 * @Date 2019/6/4 9:39
 * @Created by liushang@zsyjr.com
 * <p>
 * 这里模拟给id赋值， 这里扩展的话，可以做成  snowflake ，uuid 等自定义的程序生成id的方式
 */
@Intercepts(
        {@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})}
)
public class GenerateIdInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
        Object parameterObject = parameterHandler.getParameterObject();
        Field setId = findGeneratedValue(parameterObject);
        if (setId != null) {
            GeneratedValue annotation = setId.getAnnotation(GeneratedValue.class);
            if ("random".equalsIgnoreCase(annotation.generator())) {
                // 可以用 雪花算法(snowflake) 保证id 有序 唯一
                setId.set(parameterObject, new Random().nextInt(1000000) + "");
            } else {
                // 默认使用uuid
                setId.set(parameterObject, UUID.randomUUID().toString().replace("-", ""));

            }
        }
        return method.invoke(invocation.getTarget(), invocation.getArgs());
    }

    private Field findGeneratedValue(Object parameterObject) {
        Field[] declaredMethods = parameterObject.getClass().getDeclaredFields();
        for (Field declaredMethod : declaredMethods) {
            GeneratedValue annotation = declaredMethod.getAnnotation(GeneratedValue.class);
            if (annotation != null) {
                if (!declaredMethod.isAccessible()) {
                    declaredMethod.setAccessible(true);
                }
                return declaredMethod;
            }
        }

//        .getClass().getMethod("setId", String.class);
        return null;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
